/*
 * @Author: FBB
 * @Date: 2020-06-08 15:37:19
 * @LastEditors: FBB
 * @LastEditTime: 2020-06-09 17:14:41
 * @Description: 模拟实现ES6的Set
 *
 * 需要针对NaN做特殊处理
 */

var NaNSymbol = Symbol("NaN");

var encodeVal = function (val) {
  //判断是否为NaN
  return val !== val ? NaNSymbol : val;
};

var decodeVal = function (val) {
  return val === NaNSymbol ? NaN : val;
};

function createIterator(array, iterator) {
  var i = 0;
  function addIterator(array) {
    return {
      next() {
        return i >= array.length
          ? { done: true, vlaue: undefined }
          : { done: false, value: iterator(array[i++]) };
      },
    };
  }
  var obj = addIterator(array);
  obj[Symbol.iterator] = function () {
    return addIterator(array);
  };
  return obj;
}

function ForOf(obj, cb) {
  var result, iterable;
  if (typeof obj[Symbol.iterator] !== "function") {
    throw new TypeError("not iterable");
  }
  if (typeof cb !== "function") {
    throw new TypeError("cb must be callable");
  }
  iterable = obj[Symbol.iterator]();
  result = iterable.next();
  while (!result.done) {
    cb(result.value);
    result = iterable.next();
  }
}

function MySet(data) {
  this._value = [];
  this.size = 0;
  data && data.forEach((item) => this.add(item));
}

MySet.prototype.add = function (val) {
  val = encodeVal(val);
  if (this._value.indexOf(val) === -1) {
    this._value.push(val);
    this.size++;
  }
  return this;
};

MySet.prototype.delete = function (val) {
  const idx = this._value.indexOf(encodeVal(val));
  if (idx === -1) {
    return false;
  }
  this._value.splice(idx, 1);
  this.size--;
  return true;
};

MySet.prototype.has = function (val) {
  return this._value.indexOf(encodeVal(val)) !== -1;
};

MySet.prototype.clear = function () {
  this.size = 0;
  this._value = [];
};

MySet.prototype.forEach = function (cb, thisArg) {
  thisArg = thisArg || window;
  for (var i = 0; i < this._value.length; i++) {
    cb.call(thisArg, this._value[i], this);
  }
};

MySet.prototype.values = MySet.prototype.keys = function () {
  return createIterator(this._value, function (val) {
    return decodeVal(val);
  });
};

MySet.prototype.entries = function () {
  return createIterator(this._value, function (val) {
    return [decodeVal(val), decodeVal(val)];
  });
};
